﻿using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Utilities.DynamicValues;

namespace Tests
{
    [TestFixture]
    public sealed class DynamicValueCompilerTests
    {
        // ReSharper disable ClassNeverInstantiated.Global
        // ReSharper disable MemberCanBePrivate.Global
        public class NonFrameworkType { }
        // ReSharper restore MemberCanBePrivate.Global
        // ReSharper restore ClassNeverInstantiated.Global

        // ReSharper disable MemberCanBePrivate.Global
        public static class IndirectNonFrameworkType { public static int Value { get { return 42; } } }
        // ReSharper restore MemberCanBePrivate.Global

        [Test]
        public void TestInt32Value()
        {
            DynamicValueCompiler<int> dynamicValueCompiler = new DynamicValueCompiler<int>();
            int value = dynamicValueCompiler.GetOrCompile("42");
            Assert.That(value, Is.EqualTo(42));
        }

        [Test]
        public void TestLambdaValue()
        {
            DynamicValueCompiler<Func<int, int>> dynamicValueCompiler = new DynamicValueCompiler<Func<int, int>>();
            Func<int, int> value = dynamicValueCompiler.GetOrCompile("x => x + 42");
            Assert.That(value(1), Is.EqualTo(43));
        }

        [Test]
        public void TestValueTypeIsImplicitlyImported()
        {
            DynamicValueCompiler<NonFrameworkType> dynamicValueCompiler = new DynamicValueCompiler<NonFrameworkType>();
            NonFrameworkType value = dynamicValueCompiler.GetOrCompile("new DynamicValueCompilerTests.NonFrameworkType()");
            Assert.That(value, Is.InstanceOf<NonFrameworkType>());
        }

        [Test]
        public void TestTypesInsideGenericValueTypeAreImplicitlyImported()
        {
            DynamicValueCompiler<Func<NonFrameworkType>> dynamicValueCompiler = new DynamicValueCompiler<Func<NonFrameworkType>>();
            Func<NonFrameworkType> value = dynamicValueCompiler.GetOrCompile("() => new DynamicValueCompilerTests.NonFrameworkType()");
            Assert.That(value(), Is.InstanceOf<NonFrameworkType>());
        }

        [Test]
        public void TestTypesCanBeExplicitlyImported()
        {
            DynamicValueCompiler<int> dynamicValueCompiler = new DynamicValueCompiler<int>();

            // without import
            Assert.That(() => dynamicValueCompiler.GetOrCompile("DynamicValueCompilerTests.IndirectNonFrameworkType.Value"), Throws.InstanceOf<DynamicCompilationException>());

            // with import
            int value = dynamicValueCompiler.GetOrCompile("DynamicValueCompilerTests.IndirectNonFrameworkType.Value", typeof(IndirectNonFrameworkType));
            Assert.That(value, Is.EqualTo(IndirectNonFrameworkType.Value));
        }

        [Test]
        public void LinqCanBeUsed()
        {
            DynamicValueCompiler<Func<IEnumerable<string>, bool>> dynamicValueCompiler = new DynamicValueCompiler<Func<IEnumerable<string>, bool>>();

            // without import
            Assert.That(() => dynamicValueCompiler.GetOrCompile("e => e.Any(String.IsNullOrEmpty)"), Throws.InstanceOf<DynamicCompilationException>());

            // with import
            var func = dynamicValueCompiler.GetOrCompile("e => e.Any(String.IsNullOrEmpty)", typeof(Enumerable));
            Assert.False(func(new[] { "asd", "asd" }));
            Assert.True(func(new[] { "asd", "" }));
        }
    }
}